from lexer import *

type_list = ["char", "integer", "array"]
type_mapping = []


def indent(level):
    return "  " * level


def match(tokens, expected):
    expected_type, expected_value = expected
    if tokens:
        if tokens[0].token_type == expected_type and tokens[0].value == expected_value:
            tokens.pop(0)
        elif expected_value == "type_":
            # print(type_list)
            if tokens[0].value in type_list:
                tokens.pop(0)
        else:
            raise Exception(
                f"curTokens:'{tokens}' "
                f"Syntax error: Expected '{expected_value},{expected_type}', got '{tokens[0].value if tokens else 'EOF'},"
                f"{tokens[0].token_type}'")


def parse_program(tokens):
    tree = []
    tree.append("Program:")
    match(tokens, (RESERVED, "program"))
    tree.append(indent(1) + f"ID: {tokens[0].value}")
    match(tokens, (ID, tokens[0].value))
    tree.extend(parse_declarations(tokens, 1))
    match(tokens, (RESERVED, "begin"))
    tree.extend(parse_statement_list(tokens, 1))
    match(tokens, (RESERVED, "end"))
    match(tokens, (SINGLE_DELIMITER, "."))
    return tree


def parse_declarations(tokens, level):
    # 下面的所有level都需要改为和level相关,别用具体数字
    tree = []
    tree.append(indent(level) + "Declarations:")

    while tokens and tokens[0].value != "begin":
        if tokens[0].value == "var":
            # var integer a 语法树需要显示具体类型 不可以只是ID
            match(tokens, (RESERVED, "var"))
            curType = tokens[0].value.upper()
            match(tokens, (RESERVED, "type_"))
            tree.extend(parse_ID_list(tokens, level + 1, curType))
            match(tokens, (SINGLE_DELIMITER, ";"))
        elif tokens[0].value == "type":
            tree.extend(parse_type_list(tokens, level + 1))
            # tree.append(indent(level + 1) + "Type:")
            # # type t = integer;
            # match(tokens, (RESERVED, "type"))
            # curType = tokens[0].value
            # match(tokens, (ID, tokens[0].value))
            # type_list.append(curType)
            # match(tokens, (SINGLE_DELIMITER, "="))
            # match(tokens, (RESERVED, "type_"))
            # match(tokens, (SINGLE_DELIMITER, ";"))
        elif tokens[0].value == "procedure":
            # type t = integer;
            tree.append(indent(level + 1) + "Procedure:")
            match(tokens, (RESERVED, "procedure"))
            match(tokens, (ID, tokens[0].value))
            match(tokens, (SINGLE_DELIMITER, "("))
            tree.append(indent(level + 2) + "Param List:")
            while tokens[0].value != ")":
                curType = tokens[0].value.upper()
                match(tokens, (RESERVED, "type_"))

                tree.append(indent(level + 3) + f"{curType}: {tokens[0].value}")
                match(tokens, (ID, tokens[0].value))
            match(tokens, (SINGLE_DELIMITER, ")"))
            match(tokens, (SINGLE_DELIMITER, ";"))
            tree.extend(parse_declarations(tokens, level + 2))
            match(tokens, (RESERVED, "begin"))
            tree.extend(parse_statement_list(tokens, level + 2))
            match(tokens, (RESERVED, "end"))

        # elif tokens[0].value == "begin" or tokens[0].value == "end":
        #     match(tokens, (RESERVED, tokens[0].value))
        else:
            # char a
            curType = tokens[0].value.upper()
            match(tokens, (RESERVED, "type_"))
            tree.extend(parse_ID_list(tokens, level + 1, curType))
            match(tokens, (SINGLE_DELIMITER, ";"))

    return tree


def parse_ID_list(tokens, level, curType):
    tree = []
    tree.append(indent(level) + "IDList:")
    tree.append(indent(level + 1) + f"{curType}: {tokens[0].value}")
    match(tokens, (ID, tokens[0].value))
    while tokens and tokens[0].value == ",":
        match(tokens, (SINGLE_DELIMITER, ","))
        tree.append(indent(level + 1) + f"{curType}: {tokens[0].value}")
        match(tokens, (ID, tokens[0].value))
    return tree


def parse_type_list(tokens, level):

    tree = []
    tree.append(indent(level) + "TypeList:")

    while tokens and tokens[0].value == "type":
        match(tokens, (RESERVED, "type"))
        curId = tokens[0].value
        match(tokens, (ID, tokens[0].value))
        type_list.append(curId)
        match(tokens, (SINGLE_DELIMITER, "="))
        type_mapping.append({'id': curId,
                             'type': tokens[0].value})
        tree.append(indent(level + 1) + f"{curId}:{tokens[0].value.upper()}")
        match(tokens, (RESERVED, "type_"))
        match(tokens, (SINGLE_DELIMITER, ";"))
    return tree


def parse_statement_list(tokens, level):
    tree = []
    tree.append(indent(level) + "StatementList:")
    while tokens:
        if tokens[0].value == ";":
            match(tokens, (SINGLE_DELIMITER, ";"))
        if tokens[0].value == "read" or tokens[0].value == "write":
            curOp = tokens[0].value

            match(tokens, (RESERVED, tokens[0].value))
            match(tokens, (SINGLE_DELIMITER, '('))
            tree.append(indent(level + 1) + curOp.upper() + " OP: " + tokens[0].value)
            # tree.append(indent(level + 2) + tokens[0].value)
            match(tokens, (ID, tokens[0].value))
            match(tokens, (SINGLE_DELIMITER, ')'))
            match(tokens, (SINGLE_DELIMITER, ";"))

        if tokens[0].value == "if":
            # 此处也可以是一个if嵌套的 但是实现的是最简单的结构
            tree.append(indent(level + 1) + "IF")
            match(tokens, (RESERVED, "if"))
            tree.extend(parse_statement(tokens, level + 1))

            # 处理then
            match(tokens, (RESERVED, "then"))
            tree.append(indent(level + 2) + "THEN:")
            tree.extend(parse_statement(tokens, level + 2))
            # 处理else
            match(tokens, (RESERVED, "else"))
            tree.append(indent(level + 2) + "ELSE:")
            tree.extend(parse_statement(tokens, level + 2))
            # 处理fi
            match(tokens, (RESERVED, "fi"))
            match(tokens, (SINGLE_DELIMITER, ";"))

        if tokens[0].value == "end":
            break
            # if len(tokens)>=2 and tokens[1]==".":
            #     break
            # else:
            #     match(tokens, (RESERVED, "end"))
        tree.extend(parse_statement(tokens, level + 1))
    return tree


def parse_statement(tokens, level):
    tree = []
    tree.append(indent(level) + "Statement:")
    tree.append(indent(level + 1) + f"ID: {tokens[0].value}")
    match(tokens, (ID, tokens[0].value))
    cur_op = tokens[0].value
    if tokens[0].value == ":=":
        match(tokens, (DOUBLE_DELIMITER, ":="))
        tree.extend(parse_expression(tokens, level + 1, cur_op))
    elif tokens[0].value in "<>":
        match(tokens, (SINGLE_DELIMITER, tokens[0].value))
        tree.extend(parse_expression(tokens, level + 1, cur_op))
    else:
        # 函数调用
        match(tokens, (SINGLE_DELIMITER, '('))
        tree.extend(parse_expression(tokens, level + 1, cur_op="CALL"))
        match(tokens, (SINGLE_DELIMITER, ')'))

    return tree


def parse_expression(tokens, level,cur_op):
    tree = []
    # 提现出什么表达式
    tree.append(indent(level) + "Operation "+cur_op.upper())
    tree.extend(parse_term(tokens, level + 1))

    while tokens and tokens[0].value in ["+", "-"]:
        tree.append(indent(level + 1) + f"Op: {tokens[0].value}")
        match(tokens, (tokens[0].token_type, tokens[0].value))
        tree.extend(parse_term(tokens, level + 1))
    return tree


def parse_term(tokens, level):
    tree = []
    tree.append(indent(level) + "Term:")
    tree.extend(parse_factor(tokens, level + 1))

    while tokens and tokens[0].value in ("*", "/"):
        tree.append(indent(level + 1) + f"Op: {tokens[0].value}")
        match(tokens, (SINGLE_DELIMITER, tokens[0].value))
        tree.extend(parse_factor(tokens, level + 1))
    return tree


def parse_factor(tokens, level):
    tree = []
    if tokens[0].token_type == ID:
        tree.append(indent(level) + f"ID: {tokens[0].value}")
        match(tokens, (ID, tokens[0].value))
    elif tokens[0].token_type == INTEGER:
        tree.append(indent(level) + f"INTEGER: {tokens[0].value}")
        match(tokens, (INTEGER, tokens[0].value))
    elif tokens[0].token_type == CHAR:
        tree.append(indent(level) + f"CHAR: {tokens[0].value}")
        match(tokens, (CHAR, tokens[0].value))
    else:
        # tree.append(indent(level) + "Call:")
        match(tokens, (SINGLE_DELIMITER, "("))
        tree.extend(parse_expression(tokens, level + 1,cur_op=""))
        match(tokens, (SINGLE_DELIMITER, ")"))
    return tree


def print_tree(tree):
    for node in tree:
        print(node)
